import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server{
	
	private static final int CONSOLE_PORT_NUMBER = 8000;
	private static final int MAX_USERS = 2;
	
	boolean connected;
	
	User[] users;
	ServerSocket ss;
	
	Socket console;
	Socket chat;
	
	ObjectOutputStream console_out;
	ObjectInputStream console_in;
	
	ObjectOutputStream chat_input;
	ObjectInputStream chat_output;
	
	public Server(){
		
		users = new User[10];
		
		//2 Hard coded users for the sake of the project
		users[0] = new User("Alice", "12345");
		users[1] = new User("Bob", "23456");
		
		//WARNING!  If this does not execute properly, the Server will be improperly constructed.
		try{
			ss = new ServerSocket(CONSOLE_PORT_NUMBER, 10);
		}
		catch(IOException e){
			
			e.printStackTrace();
		}
	}
	
	public void run(){
		
		int cursor = -1;
		
		System.out.println("Waiting for connection...");
		
		try{
			
			//accept a connection from the client
			console = ss.accept();
			System.out.println("Connection received from " + console.getInetAddress().getHostName());
			
			console_out = new ObjectOutputStream(console.getOutputStream());
			console_out.flush();
			console_in = new ObjectInputStream(console.getInputStream());
			
			//Connection has been successfully established
			connected = true;
			
			try{
				
				while(connected){
					
//					DEBUG OUTPUT
					System.out.println("Waiting for input...");
					cursor = console_in.readInt();
					
					switch(cursor){
						
						case 0:{
							
							//Once this control block is reached, the system expects 2 more strings, and returns a boolean
							console_out.writeBoolean(validateUser((String) console_in.readObject(), (String) console_in.readObject()));
							
							break;
						}
						//Connect to the server
						case 1:{
							
//							DEBUG OUTPUT
							System.out.println("**Received 1**");
							
							String[] output = new String[MAX_USERS];
							
							for(int i = 0; i < MAX_USERS; i++){
								
								output[i] = users[i].getName();
							}

							console_out.writeObject(output);
							
							break;
						}
						//Send a message
						case 2:{
							
//							DEBUG OUTPUT
							System.out.println("**Received 2**");
							
							String target = (String) console_in.readObject();
							String source = (String) console_in.readObject();
							String content = (String) console_in.readObject();
							Message output = null;
							
							if(findUserByName(target) >= 0){
								
								int to_id = (int) findUserByName(target); 
								int from_id = (int) findUserByName(source);
								
								//New Message: content, to, from
								output = new Message(content, to_id, from_id);
								
								//Add the message to the user's inbox
								users[to_id].leaveMessage(output);
								
								console_out.writeBoolean(true);
							}
							else{
								
								console_out.writeBoolean(false);
							}
							
							break;
						}
						//Receive messages
						case 3:{
							
//							DEBUG OUTPUT
							System.out.println("**Received 3**");
							
							String name = (String) console_in.readObject();
							
							int client_id = (int) findUserByName(name);
							
							String[] output = users[client_id].readMessages();
							
							console_out.writeObject(output);
							console_out.writeInt(users[client_id].getNumberOfMessages());
							break;
						}
						//Start chat
						case 4:{
							
//							DEBUG OUTPUT
							System.out.println("**Received 4**");
							
							break;
						}
						//Enter chat
						case 5:{
							
//							DEBUG OUTPUT
							System.out.println("**Received 5**");
							
							break;
						}
						//Exit application
						case 6:{
							
//							DEBUG OUTPUT
//							System.out.println("**Received 6**");
							
							disconnectConsole();
							break;
						}
						//Continue execution - incorrect entry
						default:{
							
							System.out.println("Please send a correct value!");
						}
					}
					
//					DEBUG OUTPUT
//					System.out.println("Console flushing now...");
					console_out.flush();
				}
			}
			catch(ConnectException e){
				
				System.out.println("**Connection Terminated**");
			}
			catch(IOException e){
				
				e.printStackTrace();
			}
			catch(ClassNotFoundException e){
				
				e.printStackTrace();
			}
		}
		catch(IOException e){
			
			e.printStackTrace();
		}
	}
	
	private void disconnectConsole(){
		
		connected = false;
		
		try{
			
//			DEBUG OUTPUT
//			System.out.println("Sending disconnect acknowledgment now!");
			
			console_out.writeBoolean(false);
		}catch(IOException e){
			
			e.printStackTrace();
		}
	}
	
	/*
	 * Method that finds the users ID by their name.  Returns -1 if no user is found!
	 */
	private long findUserByName(String name){
		
		for(int i = 0; i < MAX_USERS; i++){
			
			if(users[i].getName().equals(name)){
				
				return users[i].getID();
			}
		}
		
		return -1;
	}
	
	private boolean validateUser(String name, String password_attempt){
		
		for(int i = 0; i < MAX_USERS; i++){
			
			if(users[i].getName().equals(name) && users[i].validate(password_attempt)){
				
				System.out.println("**Acknowledged User: " + users[i].getName() + "**");
				return true;
			}
		}
		
		return false;
	}
	
	public static void main(String[] args){
		
		Server s = new Server();
		
		while(true)
		{
			s.run();
		}
	}
}